package com.tian.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSON;
import com.tian.config.RedisConfig;
import com.tian.convert.DataConvertUtil;
import com.tian.dto.InvitedDto;
import com.tian.dto.QueryUserReqDto;
import com.tian.dto.QueryUserRespDto;
import com.tian.dto.RegisterReqDto;
import com.tian.entity.GlobalProperty;
import com.tian.entity.InvitedIncomeRecord;
import com.tian.entity.InvitedUserRecord;
import com.tian.entity.User;
import com.tian.enums.BusiTypeEnum;
import com.tian.enums.ResultCode;
import com.tian.mapper.InvitedIncomeRecordMapper;
import com.tian.mapper.InvitedUserRecordMapper;
import com.tian.mapper.UserMapper;
import com.tian.service.UserService;
import com.tian.util.CommonResult;
import com.tian.util.RedisConstantPre;
import com.tian.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.List;

/**
 * @author tianwc  公众号：java后端技术全栈、面试专栏
 * @version 1.0.0
 * @date 2023年05月09日 20:53
 * 博客地址：<a href="http://woaijava.cc/">博客地址</a>
 * <p>
 * 用户注册、邀请用户注册以及信息管理
 */
@Slf4j
@Service
public class UserServiceImpl implements UserService {
    @Resource
    private UserMapper userMapper;
    @Resource
    private InvitedIncomeRecordMapper invitedIncomeRecordMapper;
    @Resource
    private InvitedUserRecordMapper invitedUserRecordMapper;
    @Resource
    private RedissonClient redissonClient;
    @Resource
    private RedisConfig redisConfig;

    @Override
    public CommonResult<QueryUserRespDto> selectById(Long id) {
        User user = userMapper.selectByPrimaryKey(id);
        if (user == null) {
            return CommonResult.failed(ResultCode.VALIDATE_FAILED);
        }
        return CommonResult.success(DataConvertUtil.convert(user));
    }

    @Override
    public CommonResult<Long> add(RegisterReqDto registerReqDto) {
        return doRegister(registerReqDto.getPhone(), registerReqDto.getOpenId());
    }

    public CommonResult<Long> doRegister(String phone, String openId) {
        User user = new User();
        //由运营人员配置多少注册成功后送多少积分
        String cache = redisConfig.get(RedisConstantPre.GLOBAL_PROPERTY_PRE + BusiTypeEnum.REGISTER_TO_POINTS);
        List<GlobalProperty> globalPropertyList = JSON.parseArray(cache, GlobalProperty.class);
        int points = 0;
        if (!CollectionUtil.isEmpty(globalPropertyList)) {
            points = globalPropertyList.get(0).getBusiDefault();
        }
        user.setPhone(phone);
        user.setPoints(points);
        if (!StringUtil.isBlank(openId)) {
            user.setOpenId(openId);
        }
        int flag = userMapper.insert(user);
        if (flag == 0) {
            return CommonResult.success(user.getId());
        }
        return CommonResult.failed(ResultCode.FAILED);
    }

    /**
     * 在同一个事务中完成：
     * 1、更新邀请用户，邀请人获取收益，累加到可用余额中
     * 2、增加邀请人记录
     * 3、增加邀请人收益记录
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public CommonResult<Boolean> invitedRegister(InvitedDto invitedDto) {
        //参数非空校验  唯一索引
        User user = userMapper.selectByInvitationCode(invitedDto.getInvitedCode());
        if (user == null) {
            return CommonResult.failed(ResultCode.VALIDATE_FAILED);
        }

        String key = RedisConstantPre.INVITED_USER_REGISTER_PRE + user.getId();
        RLock rLock = redissonClient.getLock(key);
        try {

            //再查一次
            user = userMapper.selectByPrimaryKey(user.getId());

            CommonResult<Long> resultRegister = doRegister(invitedDto.getPhone(), null);
            //用户注册失败
            if (resultRegister.getCode() != ResultCode.SUCCESS.getCode()) {
                return CommonResult.failed(resultRegister.getCode(), resultRegister.getMessage());
            }

            //邀请用户注册记录
            InvitedUserRecord invitedUserRecord = new InvitedUserRecord();
            invitedUserRecord.setInvitedUserId(resultRegister.getData());
            invitedUserRecord.setCreateTime(invitedDto.getCreateTime());
            invitedUserRecord.setUserId(user.getId());
            invitedUserRecordMapper.insert(invitedUserRecord);

            //更新邀请人可用余额
            String cache = redisConfig.get(RedisConstantPre.GLOBAL_PROPERTY_PRE + BusiTypeEnum.INVITED_REGISTER_TO_BALANCE);
            List<GlobalProperty> globalPropertyList = JSON.parseArray(cache, GlobalProperty.class);
            int income = 0;
            if (!CollectionUtil.isEmpty(globalPropertyList)) {
                income = globalPropertyList.get(0).getBusiDefault();
            }
            user.setBalance(user.getBalance() + income);
            userMapper.updateByPrimaryKey(user);

            //邀请用户获取收益
            InvitedIncomeRecord invitedIncomeRecord = new InvitedIncomeRecord();
            invitedIncomeRecord.setInvitedUserRecordId(invitedUserRecord.getId());
            invitedIncomeRecord.setIncome(new BigDecimal(income));
            invitedIncomeRecord.setUserId(user.getId());
            invitedIncomeRecord.setCreateTime(invitedDto.getCreateTime());
            invitedIncomeRecordMapper.insert(invitedIncomeRecord);
        } finally {
            rLock.unlock();
        }
        return CommonResult.success(Boolean.TRUE);
    }

    @Override
    public CommonResult<QueryUserRespDto> selectByPhone(QueryUserReqDto queryUserReqDto) {
        if (StringUtil.isBlank(queryUserReqDto.getPhone())) {
            return CommonResult.failed(ResultCode.VALIDATE_FAILED, "手机号为空");
        }
        User user = userMapper.selectByPhone(queryUserReqDto.getPhone());
        if (user == null) {
            return CommonResult.failed(ResultCode.VALIDATE_FAILED);
        }
        return CommonResult.success(DataConvertUtil.convert(user));
    }
}
